package com.ziiwee.reduce.rest;

import com.ziiwee.reduce.rest.condition.Condition;
import com.ziiwee.reduce.rest.condition.parser.DefaultQLConditionParser;
import com.ziiwee.reduce.rest.utils.RestUtil;
import org.springframework.core.ResolvableType;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;

public abstract class AbstractResourceController<T extends Resource<ID>, ID> implements ResourceController<T, ID> {

    @GetMapping
    public final Page<T> findAllHandler(@PageableDefault Pageable pageable, HttpServletRequest request) {
        Condition condition = RestUtil.parseCondition(getResourceType(),request);
        return findAll(pageable, condition);
    }

    @GetMapping("/{id}")
    public final T findOneHandler(@PathVariable ID id) {
        return findOne(id);
    }

    @PostMapping
    public final T createHandler(@RequestBody @Valid T t) {
        return create(t);
    }

    @PutMapping("/{id}")
    public final T putHandler(@PathVariable ID id, @RequestBody Map<String, Object> values) {
        return update(id, values);
    }

    @PatchMapping("/{id}")
    public final T patchHandler(@PathVariable ID id, @RequestBody Map<String, Object> values) {
        return update(id, values);
    }

    @DeleteMapping("/{id}")
    public final void deleteHandler(@PathVariable ID id) {
        delete(id);
    }


    @Override
    public Page<T> findAll(Pageable pageable, Condition condition) {
        return getService().findAll(pageable, condition);
    }

    @Override
    public T findOne(ID id) {
        return getService().findOne(id);
    }

    @Override
    public T create(T t) {
        return getService().create(t);
    }

    @Override
    public T update(ID id, Map<String, Object> parameters) {
        return getService().update(id, parameters);
    }

    @Override
    public void delete(ID id) {
        getService().delete(id);
    }


    protected final Class<T> getResourceType() {
        try {
            List<ResolvableType> typeArgs = RestUtil.getTypeArgsByInstance(this, AbstractResourceController.class);
//            List<Class<?>> typeArgs = ReflectUtil.getTypeArgs(getClass(), AbstractResourceController.class);
            @SuppressWarnings("unchecked")
            Class<T> type = (Class<T>) typeArgs.get(0).resolve();
            return type;
        } catch (Exception e) {
            throw new ResourceServiceNotFindException("无法获得 Resource 的类型 ：" + e.getMessage(), e);
        }
    }

    protected final Class<ID> getResourceIdType() {
        try {
            List<ResolvableType> typeArgs = RestUtil.getTypeArgsByInstance(this, AbstractResourceController.class);
//            List<Class<?>> typeArgs = ReflectUtil.getTypeArgs(getClass(), AbstractResourceController.class);
            @SuppressWarnings("unchecked")
            Class<ID> type = (Class<ID>) typeArgs.get(1).resolve();
            return type;
        } catch (Exception e) {
            throw new ResourceServiceNotFindException("无法获得 Resource 的类型 ：" + e.getMessage(), e);
        }
    }

}
